package com.dustedpixels.jasmin.chips.z80.impl;

import jasmin.chips.impl.Z80New;
import jasmin.chips.impl.Z80New.State;

import com.dustedpixels.jasmin.chips.z80.Z80Context;
import com.dustedpixels.jasmin.chips.z80.implbase.Z80ImplBase;

/**
 * Z80 implementation based on jasmin.chips.impl.Z80New.
 */
public final class Z80Version2 extends Z80ImplBase {
    private final Z80New impl;
    private final Z80New.State implState;

    public Z80Version2(final Z80Context context) {
        Z80New.Context implContext = new Z80New.Context() {
            public int in(int address) {
                return context.in((short) address) & 0xFF;
            }

            public boolean irq() {
                return context.isIRQActive();
            }

            public boolean nmi() {
                return context.isNMIActive();
            }

            public void out(int address, int value) {
                context.out((short) address, (byte) value);
            }

            public int peek(int address) {
                return context.peek((short) address) & 0xFF;
            }

            public void poke(int address, int value) {
                context.poke((short) address, (byte) value);
            }

            public boolean reset() {
                return context.isResetActive();
            }

            public State state() {
                return null;
            }            
        };
        
        this.impl = new Z80New(implContext);
        this.implState = new Z80New.State();
    }
    
    public byte getA() {
        impl.writeState(implState);
        return (byte) implState.A;
    }

    public byte getA2() {
        impl.writeState(implState);
        return (byte) implState.A_BIS;
    }

    public byte getB() {
        impl.writeState(implState);
        return (byte) (implState.BC >>> 8);
    }

    public byte getB2() {
        impl.writeState(implState);
        return (byte) (implState.BC_BIS >>> 8);
    }

    public byte getC() {
        impl.writeState(implState);
        return (byte) implState.BC;
    }

    public byte getC2() {
        impl.writeState(implState);
        return (byte) implState.BC_BIS;
    }

    public long getCycles() {
        return impl.getTicks();
    }

    public byte getD() {
        impl.writeState(implState);
        return (byte) (implState.DE >>> 8);
    }

    public byte getD2() {
        impl.writeState(implState);
        return (byte) (implState.DE_BIS >>> 8);
    }

    public byte getE() {
        impl.writeState(implState);
        return (byte) implState.DE;
    }

    public byte getE2() {
        impl.writeState(implState);
        return (byte) implState.DE_BIS;
    }

    public byte getF() {
        impl.writeState(implState);
        return (byte) implState.F;
    }

    public byte getF2() {
        impl.writeState(implState);
        return (byte) implState.F_BIS;
    }

    public byte getH() {
        impl.writeState(implState);
        return (byte) (implState.HL >>> 8);
    }

    public byte getH2() {
        impl.writeState(implState);
        return (byte) (implState.HL_BIS >>> 8);
    }

    public byte getI() {
        impl.writeState(implState);
        return (byte) implState.I;
    }

    public boolean getIFF1() {
        impl.writeState(implState);
        return implState.IFF1;
    }

    public boolean getIFF2() {
        impl.writeState(implState);
        return implState.IFF2;
    }

    public byte getIM() {
        impl.writeState(implState);
        return (byte) implState.IM;
    }

    public short getIX() {
        impl.writeState(implState);
        return (short) implState.IX;
    }

    public short getIY() {
        impl.writeState(implState);
        return (short) implState.IY;
    }

    public byte getL() {
        impl.writeState(implState);
        return (byte) implState.HL;
    }

    public byte getL2() {
        impl.writeState(implState);
        return (byte) implState.HL_BIS;
    }

    public short getPC() {
        impl.writeState(implState);
        return (short) implState.PC;
    }

    public byte getR() {
        impl.writeState(implState);
        return (byte) implState.R;
    }

    public short getSP() {
        impl.writeState(implState);
        return (short) implState.SP;
    }

    public void processInstruction() {
        impl.processSlice();
    }

    public void setA(byte value) {
        impl.writeState(implState);
        implState.A = value & 0xFF;
        impl.readState(implState);
    }

    public void setA2(byte value) {
        impl.writeState(implState);
        implState.A_BIS = value & 0xFF;
        impl.readState(implState);
    }

    public void setB(byte value) {
        impl.writeState(implState);
        implState.BC = (implState.BC & 0x00FF) | ((value & 0xFF) << 8);
        impl.readState(implState);
    }

    public void setB2(byte value) {
        impl.writeState(implState);
        implState.BC_BIS = (implState.BC_BIS & 0x00FF) | ((value & 0xFF) << 8);
        impl.readState(implState);
    }

    public void setC(byte value) {
        impl.writeState(implState);
        implState.BC = (implState.BC & 0xFF00) | (value & 0xFF);
        impl.readState(implState);
    }

    public void setC2(byte value) {
        impl.writeState(implState);
        implState.BC_BIS = (implState.BC_BIS & 0xFF00) | (value & 0xFF);
        impl.readState(implState);
    }

    public void setD(byte value) {
        impl.writeState(implState);
        implState.DE = (implState.DE & 0x00FF) | ((value & 0xFF) << 8);
        impl.readState(implState);
    }

    public void setD2(byte value) {
        impl.writeState(implState);
        implState.DE_BIS = (implState.DE_BIS & 0x00FF) | ((value & 0xFF) << 8);
        impl.readState(implState);
    }

    public void setE(byte value) {
        impl.writeState(implState);
        implState.DE = (implState.DE & 0xFF00) | (value & 0xFF);
        impl.readState(implState);
    }

    public void setE2(byte value) {
        impl.writeState(implState);
        implState.DE_BIS = (implState.DE_BIS & 0xFF00) | (value & 0xFF);
        impl.readState(implState);
    }

    public void setF(byte value) {
        impl.writeState(implState);
        implState.F = value & 0xFF;
        impl.readState(implState);
    }

    public void setF2(byte value) {
        impl.writeState(implState);
        implState.F_BIS = value & 0xFF;
        impl.readState(implState);
    }

    public void setH(byte value) {
        impl.writeState(implState);
        implState.HL = (implState.HL & 0x00FF) | ((value & 0xFF) << 8);
        impl.readState(implState);
    }

    public void setH2(byte value) {
        impl.writeState(implState);
        implState.HL_BIS = (implState.HL_BIS & 0x00FF) | ((value & 0xFF) << 8);
        impl.readState(implState);
    }

    public void setI(byte value) {
        impl.writeState(implState);
        implState.I = value & 0xFF;
        impl.readState(implState);
    }

    public void setIFF1(boolean value) {
        impl.writeState(implState);
        implState.IFF1 = value;
        impl.readState(implState);
    }

    public void setIFF2(boolean value) {
        impl.writeState(implState);
        implState.IFF2 = value;
        impl.readState(implState);
    }

    public void setIM(byte value) {
        impl.writeState(implState);
        implState.IM = value;
        impl.readState(implState);
    }

    public void setIX(short value) {
        impl.writeState(implState);
        implState.IX = value & 0xFFFF;
        impl.readState(implState);
    }

    public void setIY(short value) {
        impl.writeState(implState);
        implState.IY = value & 0xFFFF;
        impl.readState(implState);
    }

    public void setL(byte value) {
        impl.writeState(implState);
        implState.HL = (implState.HL & 0xFF00) | (value & 0xFF);
        impl.readState(implState);
    }

    public void setL2(byte value) {
        impl.writeState(implState);
        implState.HL_BIS = (implState.HL_BIS & 0xFF00) | (value & 0xFF);
        impl.readState(implState);
    }

    public void setPC(short value) {
        impl.writeState(implState);
        implState.PC = value & 0xFFFF;
        impl.readState(implState);
    }

    public void setR(byte value) {
        impl.writeState(implState);
        implState.R = value & 0xFF;
        impl.readState(implState);
    }

    public void setSP(short value) {
        impl.writeState(implState);
        implState.SP = value & 0xFFFF;
        impl.readState(implState);
    }
}
